package cn.itcast.nems.enrol.web.controller.o;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.itcast.ic.common.bean.BizError;
import cn.itcast.ic.common.exception.BizException;
import cn.itcast.nems.common.captcha.SmsCaptchaService;
import cn.itcast.nems.common.enumeration.CustomBizError;
import cn.itcast.nems.enrol.api.EnrolApi;
import cn.itcast.nems.enrol.command.EnrolQuickCmd;
import cn.itcast.nems.enrol.dto.*;
import cn.itcast.nems.enrol.service.EnrolQuickService;
import cn.itcast.nems.enrol.service.EnrolService;
import cn.itcast.nems.enrol.web.converter.QuickEnrolConverter;
import cn.itcast.nems.enrol.web.vo.*;
import cn.itcast.nems.manager.kc.model.AccessTokenModel;
import cn.itcast.nems.manager.util.CustomBeanUtil;
import cn.itcast.nems.order.dto.CreateOrderResultDTO;
import cn.itcast.nems.order.dto.NewOrderDTO;
import cn.itcast.nems.order.service.OrderService;
import cn.itcast.nems.order.web.util.OrderUtil;
import cn.itcast.nems.order.web.vo.NewOrderVO;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 报名页面接口
 * </p>
 *
 * @author zhouwei
 * @since 2023/9/8 9:42 AM
 **/
@RestController
@RequestMapping("/o/enrol")
@Slf4j
@RequiredArgsConstructor
public class EnrolController {
    private final EnrolService enrolService ;
    private final EnrolApi enrolApi ;
    private final OrderService orderService;
    private final EnrolQuickService enrolQuickService;
    private final SmsCaptchaService smsCaptchaService;
    
    /**
     * 确认报名
     * @param formVO 请求参数
     * @return 响应正文、  订单号、支付链接等信息
     */
    @PostMapping("/confirm")
    public ResponseEntity<?> confirm(@RequestBody EnrolFormVO formVO) {
        log.info("[确认报名] 请求参数: {}", JSON.toJSONString(formVO));
        // 检验参数
        this.validateConfirmParam(formVO);
        EnrolOrderVO orderVO = formVO.getOrder();
        EnrolFormDTO formDTO = CustomBeanUtil.copyProperties(formVO, new EnrolFormDTO());
        EnrolOrderDTO enrolOrderDTO = CustomBeanUtil.copyProperties(orderVO, new EnrolOrderDTO());
        EnrolCustomerDTO customerDTO = CustomBeanUtil.copyProperties(orderVO.getCustomer(), new EnrolCustomerDTO());
        enrolOrderDTO.setCustomer(customerDTO);
        // 如果是新订单 , 会出现只有订单头 , 没有订单行的情况
        if (CollectionUtil.isNotEmpty(orderVO.getOrderLineList())) {
            List<EnrolOrderLineDTO> enrolOrderList = orderVO.getOrderLineList().stream()
                    .map(item -> CustomBeanUtil.copyProperties(item, new EnrolOrderLineDTO())).toList();
            enrolOrderDTO.setOrderLineList(enrolOrderList);
        }
        formDTO.setOrder(enrolOrderDTO);
        formDTO = enrolApi.confirmStudentInfo(formDTO);
        formVO  = this.transferEnrolFormVO(formDTO) ;
        log.info("[确认报名] 响应正文: {}", JSON.toJSONString(formVO));
        return ResponseEntity.ok().body(formVO);
    }

    /**
     * 老EMS报名页面生成报名连接后同步接口<br>
     * <font color="red">现已随着老EMS报名页面的下线而废弃
     * @param callbackVO 请求参数, 包含一个班级对应的多个阶段订单
     *
     * @return 响应正文
     */
    @Deprecated
    @PostMapping("/callback")
    public ResponseEntity<?> callback(@RequestBody EnrolOrderCallbackVO callbackVO) {
        log.info("[EMS报名回调接口] 请求参数: {}", JSON.toJSONString(callbackVO));
        this.validateCallbackParam(callbackVO);
        List<NewOrderDTO> orderList = callbackVO.getList().stream().map(item -> {
            // 将VO转化为 DTO实体
            NewOrderDTO orderDTO = OrderUtil.transferOrderDTO(item);
            // 维护主数据 , 如: 支付方式、业务线和订单来源
            orderService.findAndInvokeBaseData(orderDTO, item.getPaymentType(), item.getBusinessLine(), item.getOriginChannel());
            return orderDTO;
        }).toList();
        List<CreateOrderResultDTO> resultList = enrolService.callback(orderList, callbackVO.getHistoryBizOrderNoList());
        return ResponseEntity.ok().body(resultList);
    }

    /**
     * 校验EMS回调接口请求参数
     * @param callbackVO 请求参数
     */
    private void validateCallbackParam(EnrolOrderCallbackVO callbackVO) {
        Assert.isTrue(CollectionUtil.isNotEmpty(callbackVO.getList()), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "订单列表不能为空")));
        for (NewOrderVO newOrderVO : callbackVO.getList()) {
            Assert.notNull(newOrderVO.getCustomer() , () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "客户信息不能为空")));
            Assert.isTrue(StringUtils.hasText(newOrderVO.getCustomer().getCustomerId()) , () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "客户中台ID不能为空")));
        }
    }

    /**
     * 校验确认报名请求参数
     * @param formVO 请求参数
     */
    private void validateConfirmParam(EnrolFormVO formVO) {
        Assert.notNull(formVO.getOrder(), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "订单头不能为空")));
        EnrolOrderVO orderDTO = formVO.getOrder() ;
        Assert.isTrue(CollectionUtil.isNotEmpty(orderDTO.getOrderLineList()), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "订单行不能为空")));
        Assert.isTrue(StringUtils.hasText(orderDTO.getPaymentTypeCode()), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "支付方式不能为空")));
        Assert.notNull(orderDTO.getCustomer(), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "客户信息不能为空")));
        for (EnrolOrderLineVO orderLineVO : orderDTO.getOrderLineList()) {
            Assert.isTrue(StringUtils.hasText(orderLineVO.getSchoolId()), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "校区不能为空")));
            Assert.isTrue(StringUtils.hasText(orderLineVO.getModelId()), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "授课模式不能为空")));
            Assert.isTrue(StringUtils.hasText(orderLineVO.getClassTypeId()), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "班级类型不能为空")));
            Assert.isTrue(StringUtils.hasText(orderLineVO.getSubjectId()), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "学科不能为空")));
            Assert.notNull(orderLineVO.getFirstPayment(), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "首次支付金额不能为空")));
        }
    }
    /**
     * 生成报名链接
     * @param createVO 请求参数
     * @return 报名链接
     */
    @PostMapping("/url")
    public ResponseEntity<?> url(@RequestBody EnrolCreateVO createVO ) {
        log.info("[生成报名链接] 请求参数: {}",JSON.toJSONString(createVO));
        this.validateEnrolCreateVO(createVO);
        String url = enrolService.url(createVO) ;
        return ResponseEntity.ok().body(url)  ;
    }

    /**
     * 校验 生成报名链接请求参数
     * @param createVO 请求参数
     */
    private void validateEnrolCreateVO(EnrolCreateVO createVO ) {
        Assert.isTrue(Objects.nonNull(createVO.getCid()) || Objects.nonNull(createVO.getMdid()), () ->
                new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "cid和mid不能同时为空")));
        Assert.isTrue(StringUtils.hasText(createVO.getBusinessLineCode()), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "业务线不能为空")));
        Assert.isTrue(StringUtils.hasText(createVO.getOriginChannelCode()), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "订单来源不能为空")));
    }

    /**
     * 验证 sid ,并获取 oautn 认证  token
     *
     * @param sid 生成报名页面URL 序列号
     * @return token
     */
    @GetMapping("/token")
    public ResponseEntity<?> getToken(String sid) {
        if (!StringUtils.hasText(sid)) {
            throw new BizException(BizError.PARAMETER_ERROR);
        }
        log.info("[报名页面获取token] 请求参数 sid: {}" , sid);
        AccessTokenModel<?> accessTokenModel = enrolService.getToken(sid);
        log.info("[报名页面获取token] 响应结果: {}" , accessTokenModel);
        return ResponseEntity.ok().body(accessTokenModel);
    }
    /**
     * 获取报名页面详情
     *
     * @param queryVO 请求参数 sid
     * @return token
     */
    @PostMapping("/detail")
    public ResponseEntity<?> detail(@RequestBody @Validated EnrolQueryVO queryVO) {
        log.info("[获取报名页面详情] 请求参数: {}", JSON.toJSONString(queryVO));
        EnrolFormDTO formDTO = enrolApi.getEnrolInfo(new EnrolQueryDTO(queryVO.getSid()));
        EnrolFormVO formVO = this.transferEnrolFormVO(formDTO) ;
        log.info("[获取报名页面详情] 响应正文: {}", JSON.toJSONString(formVO));
        return ResponseEntity.ok().body(formVO);
    }

    private EnrolFormVO transferEnrolFormVO(EnrolFormDTO formDTO) {
        EnrolFormVO formVO = CustomBeanUtil.copyProperties(formDTO, new EnrolFormVO());
        EnrolOrderDTO orderDTO = formDTO.getOrder();
        EnrolOrderVO enrolOrderVO = CustomBeanUtil.copyProperties(orderDTO, new EnrolOrderVO());
        EnrolCustomerVO customerVO  = CustomBeanUtil.copyProperties(orderDTO.getCustomer() ,new EnrolCustomerVO()) ;
        enrolOrderVO.setCustomer(customerVO);
        // 如果是新订单 , 会出现只有订单头 , 没有订单行的情况
        if (CollectionUtil.isNotEmpty(orderDTO.getOrderLineList())) {
            List<EnrolOrderLineVO> enrolOrderLinelist = orderDTO.getOrderLineList().stream()
                    .map(item -> CustomBeanUtil.copyProperties(item, new EnrolOrderLineVO())).collect(Collectors.toList());
            enrolOrderVO.setOrderLineList(enrolOrderLinelist);
        }
        formVO.setOrder(enrolOrderVO);
        return formVO;
    }

    @GetMapping("/quick/school/subject/{activitCode}")
    public ResponseEntity<List<SchoolSubjectDTO>> schoolSubjects(@PathVariable("activitCode") String activitCode) {
        final List<SchoolSubjectDTO> schoolSubject = this.enrolQuickService.findSchoolSubject(activitCode);
        return ResponseEntity.ok().body(schoolSubject);
    }

    @PostMapping("/quick/{activitCode}")
    public ResponseEntity<EnrolQuickResultVO> quickEnroll(@RequestBody @Validated EnrolQuickFormVO form,
                                                          @PathVariable("activitCode") String activitCode) {
        final String smscode = form.getSmscode();
        final String smscodeToken = form.getSmscodeToken();
        if(!smsCaptchaService.verify(form.getMobile(), smscode, smscodeToken)) {
            log.debug("短信验证码校验不正确：手机号：{}，code：{}, token：{}", form.getMobile(), smscode, smscodeToken);
            throw new IllegalArgumentException("短信验证码错误，请确认后再重新输入！");
        }
        
        try {
            EnrolQuickCmd cmd = QuickEnrolConverter.formToCommand(form);
            cmd.setActivitCode(activitCode);
            final EnrolQuickResultDTO enrol = this.enrolQuickService.enrol(cmd);
            return ResponseEntity.status(HttpStatus.CREATED).body(new EnrolQuickResultVO(enrol.getEnrolLink()));
        } catch (Exception e) {
            log.error("快捷报名失败 activitCode:{} form:{}", activitCode, form, e);
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
        }
    }
}
